home *** CD-ROM | disk | FTP | other *** search
/ Tech Arsenal 1 / Tech Arsenal (Arsenal Computer).ISO / tek-02 / multi2.zip / QUEUE.PAS < prev    next >
Pascal/Delphi Source File  |  1993-01-04  |  11KB  |  276 lines

  1. {//////////////////////////////////////////////////////////////////////////////
  2. ///                                                                         ///
  3. ///           Universelle Verwaltung doppelt verketteter Listen             ///
  4. ///                                                                         ///
  5. ///                 (c) Christian Philipps, Moers                           ///
  6. ///                       im November 1988                                  ///
  7. ///                                                                         ///
  8. ///              Dieses System erfordert Turbo-Pascal V5.0                  ///
  9. ///              und die Unit CpMulti                                       ///
  10. ///                                                                         ///
  11. ///  Wann immer ein Element entfernt werden soll, das sich am Kopf bzw.     ///
  12. ///  Ende der Queue befindet, ist der Aufwand für die Löschung konstant.    ///
  13. ///  Die durchschnittliche Löschzeit bei Elementen aus der Mitte der Queue, ///
  14. ///  wächst proportional zur Anzahl der Elemente in der Kette.              ///
  15. ///                                                                         ///
  16. //////////////////////////////////////////////////////////////////////////////}
  17.  
  18. {$R-,S-,I-,D-,F-,V-,B-,N-,L-,O-}
  19.  
  20. UNIT Queue;
  21.  
  22. INTERFACE
  23.  
  24. USES CpMulti, CpMisc;
  25.  
  26. TYPE  QueuePtrType  = ^QueueRecType;
  27.       QueueRecType  = RECORD                     {Queue-Element}
  28.                         Data     : Pointer;      {Zeiger auf Datenbereich}
  29.                         Next     : QueuePtrType; {Zeiger auf nächstes Element}
  30.                         Prev     : QueuePtrType; {Zeiger auf Vorgänger}
  31.                       END;
  32.       QueDataType   = LongInt;
  33.       QueueType     = RECORD                     {Anker der Queue}
  34.                         Critical : Pointer;      {Semaphore für Update-Zugriff}
  35.                         Elements : Pointer;      {Element-Count}
  36.                         QueData  : QueDataType;  {User-Defined Data}
  37.                         First    : QueuePtrType; {Zeiger auf Queue-Anfang}
  38.                         Last     : QueuePtrType; {Zeiger auf Queue-Ende}
  39.                       END;
  40.       VergFuncType  = FUNCTION(Vergleichswert, Data:Pointer):BOOLEAN;
  41.  
  42. PROCEDURE AppendRec(VAR QueueRec:QueueType; Data:Pointer);
  43. FUNCTION  RemoveRec(VAR QueueRec:QueueType; Data:Pointer):Pointer;
  44. PROCEDURE CreQueue(VAR Q:QueueType);
  45. FUNCTION  DeleteQueue(VAR Q:QueueType):BOOLEAN;
  46. FUNCTION  FindRec(VAR QueueRec:QueueType; Vergleichswert:Pointer;
  47.                   ElemFound:VergFuncType):Pointer;
  48.  
  49. {-----------------------------------------------------------------------------}
  50.  
  51. IMPLEMENTATION
  52.  
  53. TYPE QueueErrType  = (QueCreSem, QueRemSem, QueHeap);
  54.  
  55. VAR  SearchQueue : Pointer;
  56.  
  57. {-----------------------------------------------------------------------------}
  58.  
  59. PROCEDURE QueueErr(ErrNo:QueueErrType);
  60.  
  61. BEGIN {QueueErr}
  62.   Write(^G'Queue: ');
  63.   CASE ErrNo OF
  64.     QueHeap:   Writeln('Zuwenig dynamischer Speicher vorhanden!');
  65.     QueCreSem: Writeln('Fehler beim Anlegen einer Semaphore!');
  66.     QueRemSem: Writeln('Fehler beim Löschen einer Semaphore!');
  67.   ELSE Writeln('Unbekannter Fehler: ',Byte(ErrNo));
  68.   END;
  69.   Halt(1);
  70. END;  {QueueErr}
  71.  
  72. {-----------------------------------------------------------------------------}
  73.  
  74. PROCEDURE AppendRec(VAR QueueRec:QueueType; Data:Pointer);
  75.  
  76. { Anhängen eines Elementes an die durch QueueRec verwaltete Queue.
  77.   Für das Element wird ein Verwaltungssatz angelegt. Fehlt der hierfür er-
  78.   forderliche dynamische Speicher, so wird die Aktion abgebochen!
  79.   Zum Abschluß der Aktion wird der Element-Count der Queue erhöht!
  80. }
  81.  
  82. VAR   Elem : QueuePtrType;
  83.  
  84. BEGIN {AppendRec}
  85.   IF MaxAvail < SizeOf(QueueRecType)
  86.      THEN QueueErr(QueHeap);
  87.  
  88.   SafeGetMem(Elem,SizeOf(Elem^));                {erzeuge Verwaltungssatz}
  89.   Elem^.Next := NIL;                             {Bildet das Kettenende}
  90.   Elem^.Data := Data;                            {hänge Datenbereich ein}
  91.  
  92.   WITH QueueRec DO
  93.   BEGIN
  94.     SemWait(Critical);                           {Kritischer Bereich}
  95.     IF First = NIL                               {erstes Kettenelement}
  96.        THEN First := Elem
  97.        ELSE BEGIN
  98.               Last^.Next := Elem;                {Verketten}
  99.             END;
  100.     Elem^.Prev := Last;                          {Vorgänger merken}
  101.     Last := Elem;                                {neues Kettenende merken}
  102.     SemSignal(Critical);                         {Freigeben der Queue}
  103.     SemSignal(Elements);                         {Erhöhe Anzahl Elemente}
  104.   END;
  105. END; {AppendRec}
  106.  
  107. {-----------------------------------------------------------------------------}
  108.  
  109. FUNCTION RemoveRec(VAR QueueRec:QueueType; Data:Pointer):Pointer;
  110.  
  111. {
  112.   Entfernen des Queue-Elementes auf dessen Datenbereich der Zeiger Data
  113.   verweist. Dieser Zeiger MUSS auf ein gültiges Kettenelement verweisen, da
  114.   zur Verbesserung der Performance von dieser Voraussetzung ausgegangen wird.
  115.   Fehlerhafte Datenbereichszeiger werden mit einiger Sicherheit im Nirwana
  116.   enden; günstigsten Falles jedoch mit einer ungültige Pointeroperation.
  117.   Der Verwaltungssatz zu diesem Element wird freigegeben.
  118.   ACHTUNG!!! Der Element-Count wird NICHT verändert, da in der Regel auf die
  119.   Warteschlange über ein SemWait(Elements) zugegriffen wird, wenn die Entnahme
  120.   von Daten beabsichtigt ist. Durch diesen Aufruf wurde der Element-Count be-
  121.   reits vor Aufruf von RemoveRec erniedrigt.
  122. }
  123.  
  124. LABEL ExitRemove;
  125.  
  126. VAR   Elem  : QueuePtrType;
  127.  
  128. BEGIN {RemoveRec}
  129.   RemoveRec := Data;                          { Zeiger auf Elem zurückliefern }
  130.  
  131.   WITH QueueRec DO
  132.   BEGIN
  133.     SemWait(Critical);                        { Exclusiver Zugriff erforderlich}
  134.     Elem := First;                            { für 2 Fälle zutreffend }
  135.     IF First = Last                           { nur 1 Kettenelement }
  136.        THEN BEGIN
  137.               First := NIL;
  138.               Last  := NIL;
  139.               Goto ExitRemove;
  140.             END;
  141.  
  142.     IF First^.Data = Data                     { erstes Element! }
  143.        THEN BEGIN
  144.               First := First^.Next;
  145.               First^.Prev := NIL;
  146.               Goto ExitRemove;
  147.             END;
  148.  
  149.     IF Last^.Data = Data                      { letztes Element }
  150.        THEN BEGIN
  151.               Elem := Last;                   { für FreeMem }
  152.               Last^.Prev^.Next := NIL;        { Vorwärtskette abschließen }
  153.               Last := Last^.Prev;             { Last aktualisieren }
  154.               Goto ExitRemove;
  155.             END;
  156.  
  157.     Elem  := First;                           { suche den Verwaltungssatz }
  158.     WHILE Elem^.Data <> Data DO
  159.       Elem := Elem^.Next;
  160.  
  161.     Elem^.Prev^.Next := Elem^.Next;           { Vorwärtsverweis durchreichen }
  162.     Elem^.Next^.Prev := Elem^.Prev;           { und rückverketten }
  163.  
  164. ExitRemove:
  165.     SafeFreeMem(Elem,SizeOf(Elem^));          { Freigeben Verwaltungssatz}
  166.     SemSignal(Critical);                      { Freigeben der Queue }
  167.   END;
  168. END;  {RemoveRec}
  169.  
  170. {-----------------------------------------------------------------------------}
  171.  
  172. PROCEDURE CreQueue(VAR Q:QueueType);
  173.  
  174. { Anlegen und Initialisieren einer Queue }
  175.  
  176. BEGIN {CreQueue}
  177.   WITH Q DO
  178.   BEGIN
  179.     IF (CreateSem(Critical) <> Sem_Ok) OR
  180.        (CreateSem(Elements) <> Sem_Ok)
  181.        THEN QueueErr(QueCreSem);
  182.  
  183.     SemClear(Elements);
  184.     First     := NIL;
  185.     Last      := NIL;
  186.   END;
  187. END;  {CreQueue}
  188.  
  189. {-----------------------------------------------------------------------------}
  190.  
  191. FUNCTION DeleteQueue(VAR Q:QueueType):BOOLEAN;
  192. {
  193.   Löschen einer Queue, sofern diese derzeit keine Elemente enthält.
  194.   Aller durch die Semaphoren belegte Speicherplatz wird wieder freigegeben.
  195.   Ist die Warteschlange einer Semaphore nicht leer, oder enthält die Queue
  196.   noch Elemente, so zeigt der Funktionswert FALSE Mißerfolg an.
  197. }
  198. BEGIN {DeleteQueue}
  199.   DeleteQueue := False;
  200.   WITH Q DO
  201.   BEGIN
  202.     IF (First <> NIL)         OR
  203.        SemSoWaiting(Critical) OR
  204.        SemSoWaiting(Elements)
  205.        THEN Exit;
  206.  
  207.     IF (RemoveSem(Critical) <> Sem_OK) OR
  208.        (RemoveSem(Elements) <> Sem_OK)
  209.        THEN QueueErr(QueRemSem);
  210.   END;
  211.   DeleteQueue := True;
  212. END;  {DeleteQueue}
  213.  
  214. {-----------------------------------------------------------------------------}
  215.  
  216. FUNCTION FindRec(VAR QueueRec:QueueType; Vergleichswert:Pointer;
  217.                  ElemFound:VergFuncType):Pointer;
  218.  
  219. {
  220.   Durchsuchen einer Queue nach einem bestimmten Element.
  221.   Der Parameter Data ist ein Zeiger auf ein irgendwie geartetes Datenelement,
  222.   das die durch Func angesprochene Funktion als Vergleichswert benötigt.
  223.   Func ist ein Zeiger auf eine Funktion, die als Parameter zwei Zeiger, einen
  224.   auf den Vergleichswert und einen auf den Datenbereich eines Queue-Elements
  225.   erhält. Der Funktionswert dieser Funktion zeigt an, ob das gesuchte Element
  226.   gefunden werden konnte. True = Gefunden. Diese Funktion muß eine FAR-Funk-
  227.   tion sein, also z. B. mit dem Compilerswitch F+ compiliert worden sein.
  228.   Kann in der gesamten Queue kein passendes Element gefunden werden, so lie-
  229.   fert FindRec NIL, anderenfalls einen Zeiger auf den Datenbereich des ge-
  230.   fundenen Kettenelementes.
  231.   Während der Suche wird die Queue blockiert, um gleichzeitige Updates auszu-
  232.   schließen. Ferner wird durch die Semaphore SearchQueue gewährleistet, daß
  233.   zu einem Zeitpunkt immer nur eine Suchanforderung aktiv sein kann. Dies ist
  234.   erforderlich, da jede Suchanforderung die globale Variable ProcAddr verän-
  235.   dert, die auf die Vergleichsfunktion verweist.
  236. }
  237.  
  238. LABEL ExitFindRec;
  239.  
  240. VAR   Elem : QueuePtrType;
  241.  
  242. BEGIN {FindRec}
  243.   SemWait(SearchQueue);                          {ProcAddr exclusiv anfordern}
  244.   FindRec  := NIL;
  245.   WITH QueueRec DO
  246.   BEGIN
  247.     SemWait(Critical);                           {blockiere die Queue}
  248.     IF First = NIL
  249.        THEN Goto ExitFindRec                     {Queue leer}
  250.        ELSE Elem := First;                       {initialisiere Arbeitspointer}
  251.  
  252.     WHILE (Elem <> NIL) DO
  253.       IF ElemFound(Vergleichswert,Elem^.Data)
  254.          THEN BEGIN                              {Eintrag gefunden}
  255.                 FindRec := Elem^.Data;
  256.                 Goto ExitFindRec;
  257.               END
  258.          ELSE Elem := Elem^.Next;                {weiter mit Folgeelement}
  259.  
  260. ExitFindRec:
  261.     SemSignal(Critical);
  262.     SemSignal(SearchQueue);
  263.   END;
  264. END;  {FindRec}
  265.  
  266. {-----------------------------------------------------------------------------}
  267.  
  268. BEGIN {Initialisierung}
  269. IF CreateSem(SearchQueue) <> Sem_OK
  270.    THEN QueueErr(QueCreSem);
  271. END.  {Initialisierung}
  272.  
  273. {//////////////////////////////////////////////////////////////////////////////
  274. ///                    Ende des Moduls                                      ///
  275. //////////////////////////////////////////////////////////////////////////////}
  276.